package cz.pecinovsky.english.pojj.adv_demo.cesta_školou.hra;

import cz.pecinovsky.english.pojj.adv_framework.game_gui.IPlaceG;
import java.awt.Point;
import cz.pecinovsky.english.pojj.adv_framework.game_txt.IPlace;
import cz.pecinovsky.english.pojj.adv_framework.game_txt.IObject;

import java.util.Collection;
import java.util.Set;
import java.util.HashSet;

import static cz.pecinovsky.english.pojj.adv_demo.cesta_školou.hra.SS_CestaSkolou.*;


/**
 *  Trida Mistnost - popisuje jednotlivou místnost ve hře
 *
 *  Tato třída je součástí jednoduché textové hry.
 *
 *  "Mistnost" reprezentuje jedno místo (místnost, prostor, ..) ve scénáři
 *  hry. Místnost může mít sousední místnosti připojené přes východy. Pro
 *  každý východ si místnost ukládá odkaz na sousedící místnost (instanci
 *  třídy Mistnost).
 *
 *@author     Michael Kolling, Lubos Pavlicek, Jarmila Pavlickova
 *@created    říjen 2008 (poslední změny)
 */

class Mistnost
      implements IPlaceG   //+++ Přidáno pro zařazení do rámce
{
    private String nazev;
    private String popis;
    private Set<Mistnost> vychody;   // obsahuje sousední místnosti
    private Point  pozice;

    //+++ Přidáno pro zařazení do rámce
    /** Kolekce obsahující všechny objekty v místnosti. */
    private Set<Objekt> předměty = new HashSet<Objekt>();

    /**
     * Vytvoření místnosti (pojmenovaný prostor) se zadaným popisem, např.
     * "kuchyň", "hala", "trávník před domem"
     *
     * @param nazev  Jméno místnosti, jednoznačný identifikátor,
     *               jedno slovo nebo víceslovný název bez .
     * @param popis  Popis místnosti.
     * @param x      Vodorovná souřadnice hráče na plánku při pobytu v místosti
     * @param y      Svislá souřadnice hráče na plánku při pobytu v místosti
     * @param objekty Názvy objektů vyskytujících se na počátku hry v místnosti
     */
    Mistnost(String nazev, String popis,
                    int x, int y,
                    String... objekty     //+++ Přidáno pro zařazení do rámce
           )
    {
        this.nazev = nazev;
        this.popis = popis;
        vychody = new HashSet<Mistnost>();

        //+++ Přidáno pro zařazení do rámce
        for (String název : objekty) {
            předměty.add(new Objekt(název));
        }
        pozice = new Point(x, y);
    }

    /**
     * Definuje východ z místnosti (sousední/vedlejsi místnost). Vzhledem k tomu, že je použit
     * Set pro uložení východů, může být sousední místnost uvedena pouze jednou
     * (tj. nelze mít dvoje dveře do stejné sousední místnosti). Druhé zadání
     * stejné místnosti tiše přepíše předchozí zadání (neobjeví se žádné chybové hlášení).
     * Lze zadat též cestu ze do sebe sama.
     *
     * @param vedlejsi mistnost, ktera sousedi s aktualni mistnosti.
     *
     */
    public void setVychod(Mistnost vedlejsi) {
        vychody.add(vedlejsi);
    }

    /**
     * Metoda equals pro porovnání dvou místností. Překrývá se metoda equals ze třídy Object.
     * Dvě místnosti jsou shodné, pokud mají stejné jméno.
     * Tato metoda je důležitá z hlediska správného fungování seznamu místností (Set).
     *
     * Bližší popis metody equals je u třídy Object.
     *
     *@param   o  object, který se má porovnávat s aktuálním
     *@return     hodnotu true, pokud zadaná místnost má stejné jméno, jinak false
     */
    @Override
    public boolean equals (Object o) {
        if (o instanceof Mistnost) {
            Mistnost druha = (Mistnost)o;
            return nazev.equals(druha.nazev);
        }
        else {
            return false;
        }
    }

    /**
     * metoda hashCode vraci ciselny identifikator instance, ktery se pouziva pro optimalizaci ukladani
     * v dynamickych datovych strukturach. Pri prekryti metody equals je potreba prekryt i metodu hashCode.
     * Podrobny popis pravidel pro vytvareni metody hashCode je u metody hashCode ve tride Object
     */
    @Override
    public int hashCode() {
        return nazev.hashCode();
    }


    /**
     * Vrací jméno místnosti (bylo zadáno při vytváření místnosti jako
     * parametr konstruktoru)
     *
     *@return    Jméno místnosti
     */
    public String getNazev() {
        return nazev;
    }

    /**
     * Vrací "dlouhý" popis místnosti, který může vypadat následovně:
     *      Jsi v mistnosti/prostoru vstupni hala budovy VSE na Jiznim meste.
     *      vychody: chodba bufet ucebna
     *
     *@return    Dlouhý popis místnosti
     */
    public String dlouhyPopis() {
        return zJDI + popis + "\n" + seznamVychodu();
    }

    /**
     * Vrací textový řetězec, který popisuje sousední místnosti (východy) například:
     * "vychody: hala ".
     *
     *@return    Seznam sousedních místností (východů)
     */
    private String seznamVychodu() {
        String vracenyText = "vychody:";
        for (Mistnost sousedni : vychody) {
             vracenyText += " " + sousedni.getNazev();
        }
        return vracenyText;
    }

    /**
     * Vrací místnost, která sousedí s aktuální místností a jejíž jméno je zadáno
     * jako parametr. Pokud místnost s udaným jménem nesousedí s aktuální místností,
     * vrací se hodnota null.
     *
     *@param  jmenoSousedni  Jméno sousední místnosti (východu)
     *@return            Místnost, která se nachází za příslušným východem, nebo
     *                   hodnota null, pokud místnost zadaného jména není sousedem.
     */
    public Mistnost sousedniMistnost(String jmenoSousedni) {
        if (jmenoSousedni == null) {
            return null;
        }
        jmenoSousedni = jmenoSousedni.toLowerCase();
        for ( Mistnost sousedni : vychody ){
            if (sousedni.getNazev().toLowerCase().equals(jmenoSousedni)) {
                return sousedni;
            }
        }
        return null;  // místnost nenalezena
    }



//== METODY VYŽADOVANÉ IMPLEMENTOVANÝM ROZHRANÍM Z RÁMCE =======================

    /***************************************************************************
     * Vrátí název místnosti.
     *
     * @return Název místnosti
     */
    @Override
    public String getName()
    {
        return nazev;
    }


    /***************************************************************************
     * Vrátí popis místnosti, který danou místnost stručné charakterizuje.
     *
     * @return Požadovaný popis
     */
    @Override
    public String getDescription()
    {
        return popis;
    }


    /***************************************************************************
     * Vrátí kolekci předmětů nacházejících se v dané místnosti.
     *
     * @return Požadovaná kolekce
     */
    @Override
    public Collection<Objekt> getObjects()
    {
        return předměty;
    }


    /***************************************************************************
     * Vrátí kolekci místností, do nichž je možno se z teto místnosti přesunout.
     *
     * @return Požadovaná kolekce
     */
    @Override
    public Collection<Mistnost> getNeighbors()
    {
        return vychody;
    }



//== DALŠÍ METODY PŘIDANÉ PŘI ZAŘAZOVÁNÍ DO RÁMCE 101 ==========================

    /***************************************************************************
     * Odlozi zadany predmet v mistnosti.
     *
     * @param  předmět odkladany v mistnosti
     */

    void polož( Objekt předmět ) {
        předměty.add( předmět );
    }


    /***************************************************************************
     * Odebere predmet zadaneho nazvu z mistnosti.
     * Odebrat je mozne pouze zvednutelné předměty.
     *
     * @param název Nazev odebiraneho predmetu
     * @return Byl-li předmět z místnosti odebrán, vrátí tento předmět.
     *         Nebyl-li předmět zvednutelný, vrátí předmět {@link TIHA}.
     *         Nebyl-li v místnosti požadovaný předmět, vrátí {@code null}.
     */
    Objekt zvedni(String název)
    {
        String jmeno;
        Objekt nasel = null;
        for( Objekt predmet : předměty ) {
            jmeno = predmet.getName();
            if (jmeno.equalsIgnoreCase( název ))  {
                if (predmet.isTransportable())  {
                    předměty.remove(predmet);
                    nasel = predmet;
                } else {
                    nasel = Objekt.TÍHA;
                }
                break;
            }
        }
        return nasel;
    }



//== METODY VYŽADOVANÉ IMPLEMENTOVANÝM ROZHRANÍM PRO 115 =======================

    /***************************************************************************
     * Vrátí pozici místnosti na plánu hry,
     * presněji pozici hráče nacházejícícho se v dané místnosti.
     * Na této pozici bude hráč při pobytu v dané místnosti zobrazen.
     *
     * @return Požadovaná pozice
     */
    @Override
    public Point getPosition()
    {
        return pozice;
    }



//== ZDĚDĚNÉ METODY ============================================================
}

